/*=====================================================================================================================
                    Copyright(c) 2009 Geometric PLM Software Corp. All rights reserved.
                             Unpublished - All rights reserved
=======================================================================================================================
File description:
    Filename: vector_c.c
    Module  : Common module.

    This file includes the operations of the simluative vector.

=======================================================================================================================
Date               Name              Description of Change
14-Jul-2009        Penn,Xie          Initialize creation
$HISTORY$
=====================================================================================================================*/
#ifndef _cplusplus
#define _CRT_SECURE_NO_DEPRECATE
#endif

#include <stdio.h>
#include <stdlib.h>
#include <itk/mem.h>
#include <memory.h>
#include "vector_c.h"

Vector_t *VECTOR_new( int capacity, int increment )
{
    Vector_t *vector;

    vector = (Vector_t *)MEM_alloc( sizeof ( Vector_t ) );
    if ( vector == NULL ) 
    {
        return NULL;
    }
    vector->size = 0;
    vector->capacity = capacity;
    vector->increment = increment;
    vector->content = (void **)MEM_alloc( capacity * sizeof ( void * ) );
    if ( vector->content == NULL ) 
    {
        MEM_free( vector );
        return NULL;
    }
    return vector;
}

Vector_t *VECTOR_add( Vector_t *in, void *element )
{
    return VECTOR_add_n( in, 1, &element );
}

Vector_t *VECTOR_add_n( Vector_t *in, int n, void *elements[] )
{
    Vector_t *out = NULL;

    out = VECTOR_ensure_capacity ( in, n );
    if ( out == NULL ) 
    {
        return NULL;
    }
    memcpy ( &out->content[out->size], elements, n * sizeof ( void * ) );
    out->size += n;
    out->capacity -= n;
    return out;
}

Vector_t *VECTOR_insert( Vector_t *in, void *element )
{
    return VECTOR_insert_n_at ( in, 1, &element, 0 );
}

Vector_t *VECTOR_insert_n_at( Vector_t *in, int n, void *elements[], int at )
{
    Vector_t *out;

    if ( at <= in->size ) 
    {
        int i;
        out = VECTOR_ensure_capacity ( in, n );
        for ( i=in->size-1; i>=at; i-- ) 
        {
            out->content[i+n] = out->content[i];
        }
        for ( i=0; i<n; i++ ) 
        {
            out->content[i+at] = elements[i];
        }
        out->size += n;
        out->capacity -= n;
    }
    else 
    {
        printf( "vector_rem_n_at: cannot add %d elements from position %d in a vector of %d elements\n", n, at, in->size );
        out = in;
    }
    return out;
}

int VECTOR_size( const Vector_t *in )
{
    return in->size;
}

void *VECTOR_get( const Vector_t *in, int index )
{
    if (index < in->size && index >= 0)
    {
        return in->content[index];
    }
    else
        return NULL;    
}

Vector_t *VECTOR_ensure_capacity( Vector_t *in, int n )
{
    Vector_t *out;

    if ( in->capacity < n ) 
    {
        n = ( n + in->increment - 1 ) / in->increment;
        out = VECTOR_new ( in->size + ( n * in->increment ), in->increment );
        if ( out == NULL ) 
        {
            return NULL;
        }
        out->size = in->size;
        out->capacity = n * in->increment;
        memcpy ( out->content, in->content, in->size * sizeof ( void * ) );
        VECTOR_free ( in );
    }
    else 
    {
        out = in;
    }
    return out;
}

int VECTOR_rem_at( Vector_t *in, int at )
{
    return VECTOR_rem_n_at ( in, 1, at );
}

int VECTOR_rem_n_at( Vector_t *in, int n, int at )
{
    int ret;

    if ( at + n <= in->size ) 
    {
        int i;
        for ( i=at; i<in->size - n; i++ ) 
        {
            in->content[i] = in->content[i+n];
        }
        in->size -= n;
        in->capacity += n;
        ret = VECTOR_ok;
    }
    else 
    {
        printf( "vector_rem_n_at: cannot remove %d elements from position %d in a vector of %d elements\n", n, at, in->size );
        ret = VECTOR_Out_of_range;
    }

    return ret;
}

void VECTOR_free( Vector_t *in )
{
    if ( in != NULL )
    {
        MEM_free( in->content );
        MEM_free( in );
    }
}

void VECTOR_free_all( Vector_t *in )
{
    int size   = 0;
    int i      = 0;
    void *data = NULL;

    if ( in != NULL )
    {
        size = VECTOR_size( in );
        for (i = 0; i < size; i++)
        {
            data = VECTOR_get( in, i );
            if (data != NULL)
            {
                MEM_free( data );
            }
        }

        VECTOR_free( in );
    }
}
